跳到主要内容

K3s 配置 letsencrypt 域名 HTTP-01

需求

使用混合云开发,现在需要使用一台服务器专门用于暴露端口出去,因为其他的云的服务器并没办法直接使用公网 IP,所以只能使用这台服务器来做端口转发

配置 DNS 服务器

获取 Traefik 的外部 IP 或域名

kubectl get svc -n <namespace-where-traefik-is-deployed>

查找类型为 LoadBalancer 的服务,并检查 “EXTERNAL-IP” 列。可能会显示多个 IP,分别对应不同的 Node,任选一个就行了

配置 Traefik

在 K3s 中配置 Traefik 以使用 HTTPS 并利用泛域名证书可以通过以下步骤完成:

步骤 1: 获取泛域名证书

你可以使用 Let's Encrypt 来获取免费的泛域名证书,或者从其他证书颁发机构购买证书。如果你选择使用 Let's Encrypt,你可以使用 Cert-Manager 在 Kubernetes 中自动处理证书的获取和续期。

首先,安装 Cert-Manager:

kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.13.1/cert-manager.yaml

接下来,配置 ClusterIssuer(或者Issuer,取决于你的需求)以使用 ACME 协议和 Let's Encrypt。创建一个 YAML 文件,如 letsencrypt-clusterissuer.yaml,并添加以下内容:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: your-email@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: traefik

然后应用这个配置:

kubectl apply -f letsencrypt-clusterissuer.yaml

检查是否成功创建了 ClusterIssuer:

kubectl get clusterissuers

注意,这个是全局的 ClusterIssuer,它可以在任何命名空间中使用。

Let’s Encrypt 利用 ACME 协议校验域名的归属,校验成功后可以自动颁发免费证书。免费证书有效期只有90天,需在到期前再校验一次实现续期。使用 cert-manager 可以自动续期,即实现永久使用免费证书。校验域名归属的两种方式分别是 HTTP-01 和 DNS-01

HTTP-01 的校验原理:是给域名指向的 HTTP 服务增加一个临时 location。此方法仅适用于给使用 Ingress 暴露流量的服务颁发证书,并且不支持泛域名证书。例如,Let’s Encrypt 会发送 HTTP 请求到 http://<YOUR_DOMAIN>/.well-known/acme-challenge/<TOKEN>。YOUR_DOMAIN 是被校验的域名。TOKEN 是 ACME 协议客户端负责放置的文件,在此处 ACME 客户端即 cert-manager,通过修改或创建 Ingress 规则来增加临时校验路径并指向提供 TOKEN 的服务。Let’s Encrypt 会对比 TOKEN 是否符合预期,校验成功后就会颁发证书。

DNS-01 的校验原理:是利用 DNS 提供商的 API Key 拿到用户 DNS 控制权限。此方法不需要使用 Ingress,并且支持泛域名证书。在 Let’s Encrypt 为 ACME 客户端提供令牌后,ACME 客户端 cert-manager 将创建从该令牌和账户密钥派生的 TXT 记录,并将该记录放在 _acme-challenge.<YOUR_DOMAIN>。Let’s Encrypt 将向 DNS 系统查询该记录,找到匹配项即可颁发证书。

这里使用 HTTP-01 方式校验

步骤 2: 配置 Traefik IngressRoute 和 Certificate

注意,这个不是全局的,所以需要指定命名空间

创建一个 YAML 文件,如 traefik-ingressroute.yaml,并添加以下内容:

# 一旦你有了 ClusterIssuer,你就可以请求证书了。创建一个 Certificate 资源来指定你想要的证书细节:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-cert
namespace: default
spec:
secretName: wildcard-cert-secret
dnsNames:
- '*.yourdomain.com'
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: my-ingressroute
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`example.yourdomain.com`) && Path(`/`)
kind: Rule
services:
- name: your-service
port: 80
tls:
secretName: wildcard-cert-secret

这个配置做了两件事:

  1. 使用 Cert-Manager 创建一个名为 wildcard-cert 的 Certificate 对象,这个对象会向 Let's Encrypt 请求一个泛域名证书,并将证书存储在名为 wildcard-cert-secret 的 Kubernetes Secret 中。
  2. 创建一个 Traefik IngressRoute,将域名 example.yourdomain.com 的 HTTPS 流量路由到名为 your-service 的服务,并使用前面创建的证书。

应用这个配置:

kubectl apply -f traefik-ingressroute.yaml

kubectl get certificate -n default
kubectl get certificates
kubectl describe certificate wildcard-cert -n default

验证和等待证书

提交了 Certificate 请求后,cert-manager 会自动进行验证并尝试颁发证书。你可以通过以下命令查看证书的状态:

kubectl describe certificate example-com -n default

当证书成功颁发后,它将被存储在你在 Certificate 资源中指定的 secretName,即 wildcard-cert-secret。

步骤 3: 配置 DNS

确保你的域名(如 example.yourdomain.com)的 DNS 记录指向你的 K3s 集群中 Traefik 的外部 IP 地址。

步骤 4: 测试你的配置

一旦 DNS 记录生效,你应该能够通过 HTTPS 访问你的服务,并且浏览器会显示一个有效的 SSL 证书。

curl https://example.yourdomain.com

这应该返回你的服务的响应,并且你应该看到一个绿色的锁标志在浏览器的地址栏中,表明连接是安全的。

请注意,Let's Encrypt 的证书通常需要几分钟时间来颁发。你可以通过查看 Cert-Manager 的 Certificate 资源的状态来跟踪进度:

kubectl describe certificate wildcard-cert

这些步骤应该帮助你在 K3s 集群中配置 Traefik 以使用 HTTPS 和泛域名证书。如果你遇到任何问题,确保检查 Traefik 和 Cert-Manager 的日志,以获取有关可能出现的问题的更多信息。

ClusterIssuer

ClusterIssuer 是一个 Kubernetes 资源,它定义了如何从证书颁发机构获取证书。它是 Issuer 的一个扩展,它的作用域是整个集群,而不是单个命名空间。

kubectl get clusterissuer

kubectl describe clusterissuer <name-of-clusterissuer>

# 检查相关的事件
kubectl get events --field-selector involvedObject.kind=ClusterIssuer,involvedObject.name=<name-of-clusterissuer>

IngressRoute 和 ingress 区别

IngressRouteIngress 是Kubernetes中用于管理外部访问集群内服务的两种不同的资源类型,它们分别属于不同的 Ingress Controller。

Ingress

  1. 标准化Ingress是 Kubernetes 的一个核心概念,是一个API对象,它提供了 HTTP 和 HTTPS 路由到服务的规则。
  2. 兼容性:由于 Ingress 是 Kubernetes 的标准 API,它被多个 Ingress Controller 支持,如 Nginx Ingress Controller、Traefik 等。
  3. 功能限制:相较于某些特定的 Ingress Controller 提供的 CRD(自定义资源定义),Ingress 的功能可能会显得有限。例如,它不支持高级的路由规则、中间件等。

IngressRoute

kubectl get ingressroute --all-namespaces
  1. 自定义资源IngressRoute 是 Traefik Ingress Controller特有的自定义资源定义(CRD)。它不是Kubernetes的标准API,而是由Traefik提供。
  2. 高级功能IngressRoute 提供了一些 Ingress 不支持的高级功能和更灵活的配置选项,例如更复杂的路由规则、中间件的使用等。
  3. 特定于TraefikIngressRoute 仅适用于Traefik Ingress Controller,如果你决定更换Ingress Controller,你需要迁移你的 IngressRoute 资源。

选择 Ingress 还是 IngressRoute 取决于你的具体需求和使用的Ingress Controller。

  • 如果你需要跨多个Ingress Controller保持兼容性,或者你不需要特定Ingress Controller提供的高级功能,那么使用 Ingress 可能是更好的选择。
  • 如果你正在使用Traefik并且需要高级路由功能,IngressRoute 可能是更合适的选择。

在决定使用哪种资源类型时,考虑你的特定用例和需求是很重要的。

排除问题

经过上面的配置后,我发现还是无法访问,查看 Traefik 的日志,发现有这样的错误:

kubectl get pods -n kube-system
kubectl logs -n kube-system traefik-6f9cbd9bd4-8q9q9

连接超时

Error initializing issuer: Get https://acme-staging-v02.api.letsencrypt.org/directory: dial tcp: i/o timeout 

修改配置

# 每次更新都要执行一次
kubectl get deployments cert-manager -n cert-manager -o yaml > cert-manager-deployment.yaml

加上下面的配置到 Pod 的 spec 里面,让它忽略默认的 DNS

dnsPolicy: None  # 设置DNS策略
dnsConfig: # 设置DNS配置
nameservers:
- "1.1.1.1"
- "8.8.8.8"
kubectl apply -f cert-manager-deployment.yaml

检查连接超时

发现是因为防火墙的原因,所以需要开放 443 端口

重新尝试证书申请

kubectl delete certificaterequests -n drone wildcard-cert
kubectl delete orders -n drone <order-name>

References